//
//  JKWebServerManager.m
//  Baisi
//
//  Created by albert on 2018/11/23.
//  Copyright © 2018 安永博. All rights reserved.
//

#import "JKWebServerManager.h"
#import "JKWebServerHelper.h"
#import "GCDWebUploader.h"

@interface JKWebServerManager () <GCDWebUploaderDelegate>

@end

static GCDWebUploader *webUploader_;
static JKWebServerManager *defaultManager_;

@implementation JKWebServerManager

+ (JKWebServerManager *)defaultManager{
    if (!defaultManager_) {
        defaultManager_ = [[JKWebServerManager alloc] init];
    }
    return defaultManager_;
}

+ (void)startWithUploadDirectoryPath:(NSString *)directoryPath
                            delegate:(id<JKWebServerManagerDelegate>)delegate
                             success:(void(^)(NSString *url, NSString *IP, NSUInteger port))success
                             failure:(void(^)(NSError *error))failure{
    
    [self startWithUploadDirectoryPath:directoryPath delegate:delegate config:nil success:success failure:failure];
}

+ (void)startWithUploadDirectoryPath:(NSString *)directoryPath
                            delegate:(id<JKWebServerManagerDelegate>)delegate
                              config:(void(^)(JKWebServerManager *manager))config
                             success:(void(^)(NSString *url, NSString *IP, NSUInteger port))success
                             failure:(void(^)(NSError *error))failure{
    /*
    NSString *wifiSSID = [JKWebServerHelper deviceWifiSSID];
    
    if (!wifiSSID) {
        
        [self stop];
        
        NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Wifi is not connected!"}];
        
        !failure ? : failure(error);
        
        return;
    } //*/
    
    NSString *IP = [JKWebServerHelper deviceIPAdress];
    
    if (!IP) {
        
        [self stop];
        
        NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Wifi is not connected!"}];
        
        !failure ? : failure(error);
        
        return;
    }
    
    if (webUploader_.isRunning) { // 正在运行
        
        NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"GCDWebServer is running!"}];
        
        !failure ? : failure(error);
        
        return;
    }
    
    webUploader_ = [[GCDWebUploader alloc] initWithUploadDirectory:directoryPath ? directoryPath : [self defaultDirectory]];
    
    // 设置代理
    webUploader_.delegate = [JKWebServerManager defaultManager];
    
    [JKWebServerManager defaultManager].delegate = delegate;
    
    // 允许隐藏文件
    webUploader_.allowHiddenItems = YES;
    
    // 限制文件上传类型
    //webUploader_.allowedFileExtensions = @[@"doc", @"docx", @"xls", @"xlsx", @"txt", @"pdf",@"zip",@"mp3"];
    
    // 设置网页标题
    webUploader_.title = @"JKFileExplorer";
    
    // 设置展示在网页上顶部的文字 默认和title一致
    webUploader_.header = @"JKFileExplorer";
    
    // 设置展示在网页上的文字(开场白)
    webUploader_.prologue = @"<p>Welcome to JKFileExplorer</p>";
    
    // 设置展示在网页上的文字(收场白)
    webUploader_.epilogue = @"<p>Thanks for using JKFileExplorer</p>";
    
    // 设置展示在网页上的文字 最底部 通常显示版权信息等
    webUploader_.footer = @"Copyright © 2019 JKFileExplorer Inc. 保留所有权利。";
    
    // 外部自定义配置
    !config ? : config([JKWebServerManager defaultManager]);
    
    [self restartWithPort:80 success:success failure:failure];
}

+ (void)restartWithPort:(NSUInteger)port
                success:(void(^)(NSString *url, NSString *IP, NSUInteger port))success
                failure:(void(^)(NSError *error))failure{
    
    static NSInteger retryCount = 0;
    
    NSError *error = nil;
    
    NSMutableDictionary *options = nil;
    
    if (port == 80 || port == 12345 || port != 0) {
        
        options = [NSMutableDictionary dictionary];
        [options setObject:[NSNumber numberWithInteger:port] forKey:GCDWebServerOption_Port];
        [options setValue:@"" forKey:GCDWebServerOption_BonjourName];
    }
    
    BOOL startSuccess = [webUploader_ startWithOptions:options error:&error];
    
    if (error || !startSuccess) { // 启动失败
        
        retryCount++;
        
        if (retryCount == 1) {
            
            [self restartWithPort:12345 success:success failure:failure];
            
            return;
        }
        
        if (retryCount <= 3) {
            
            [self restartWithPort:0 success:success failure:failure];
            
            return;
        }
        
        retryCount = 0;
        
        if (!error) {
            
            error = [NSError errorWithDomain:NSCocoaErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"GCDWebUploader start failed."}];
        }
        
        !failure ? : failure(error);
        
    } else { // 启动成功
        
        retryCount = 0;
        
        NSString *IP = [JKWebServerHelper deviceIPAdress];
        
        NSUInteger port = webUploader_.port;
        
        NSString *url = nil;
        
        if (port == 80) {
            
            url = [NSString stringWithFormat:@"http://%@/", IP];
            
        } else {
            
            url = [NSString stringWithFormat:@"http://%@:%zd/", IP, port];
        }
        
        !success ? : success(url, IP, port);
    }
}


+ (void)stop{
    
    if ([webUploader_ isRunning]) {
        
        [webUploader_ stop];
    }
    
    webUploader_ = nil;
    
    defaultManager_ = nil;
}

/** 创建文件夹 */
+ (void)createDirectoryPath:(NSString *)directoryPath{
    
    NSError *error = nil;
    
    BOOL success = [[NSFileManager defaultManager] createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:&error];
    
    if (error || !success) { // 创建失败
        
        
    }
}

/** 创建文件夹 */
+ (void)createDefaultDirectoryPath:(NSString *)directoryPath{
    
    NSError *error = nil;
    
    BOOL success = [[NSFileManager defaultManager] createDirectoryAtPath:[self defaultDirectory] withIntermediateDirectories:YES attributes:nil error:&error];
    
    if (error || !success) { // 创建失败
        
        
    }
}

+ (NSString *)defaultDirectory{
    
    NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    
    return [documentsDirectory stringByAppendingPathComponent:[self defaultDirectoryName]];
}

+ (NSString *)defaultDirectoryName{
    
    return @"GCDWebServerDocument";
}

#pragma mark
#pragma mark - setter

- (void)setAllowedFileExtensions:(NSArray *)allowedFileExtensions{
    _allowedFileExtensions = [allowedFileExtensions copy];
    
    [webUploader_ setAllowedFileExtensions:_allowedFileExtensions];
}

- (void)setAllowHiddenItems:(BOOL)allowHiddenItems{
    _allowHiddenItems = allowHiddenItems;
    
    [webUploader_ setAllowHiddenItems:_allowHiddenItems];
}

- (void)setTitle:(NSString *)title{
    _title = [title copy];
    
    [webUploader_ setTitle:_title];
}

- (void)setHeader:(NSString *)header{
    _header = [header copy];
    
    [webUploader_ setHeader:_header];
}

- (void)setPrologue:(NSString *)prologue{
    _prologue = [prologue copy];
    
    [webUploader_ setPrologue:_prologue];
}

- (void)setEpilogue:(NSString *)epilogue{
    _epilogue = [epilogue copy];
    
    [webUploader_ setEpilogue:_epilogue];
}

- (void)setFooter:(NSString *)footer{
    _footer = [footer copy];
    
    [webUploader_ setFooter:_footer];
}

#pragma mark
#pragma mark - GCDWebUploaderDelegate

/**
  *  This method is called whenever a file has been downloaded.
  */
- (void)webUploader:(GCDWebUploader *)uploader didDownloadFileAtPath:(NSString*)path{
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(webUploader:didDownloadFileAtPath:)]) {
        
        [self.delegate webUploader:uploader didDownloadFileAtPath:path];
    }
    
    NSLog(@"JKWebServerManager-->didDownloadFileAtPath:%@", path);
}

/**
 *  This method is called whenever a file has been uploaded.
 */
- (void)webUploader:(GCDWebUploader *)uploader didUploadFileAtPath:(NSString*)path{
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(webUploader:didUploadFileAtPath:)]) {
        
        [self.delegate webUploader:uploader didUploadFileAtPath:path];
    }
    
    NSLog(@"JKWebServerManager-->didUploadFileAtPath:%@", path);
}

/**
 *  This method is called whenever a file or directory has been moved.
 */
- (void)webUploader:(GCDWebUploader *)uploader didMoveItemFromPath:(NSString*)fromPath toPath:(NSString*)toPath{
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(webUploader:didMoveItemFromPath:toPath:)]) {
        
        [self.delegate webUploader:uploader didMoveItemFromPath:fromPath toPath:toPath];
    }
    
    NSLog(@"JKWebServerManager-->didMoveItemFromPath:%@ toPath:%@", fromPath, toPath);
}

/**
 *  This method is called whenever a file or directory has been deleted.
 */
- (void)webUploader:(GCDWebUploader *)uploader didDeleteItemAtPath:(NSString*)path{
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(webUploader:didDeleteItemAtPath:)]) {
        
        [self.delegate webUploader:uploader didDeleteItemAtPath:path];
    }
    
    NSLog(@"JKWebServerManager-->didDeleteItemAtPath:%@", path);
}

/**
 *  This method is called whenever a directory has been created.
 */
- (void)webUploader:(GCDWebUploader *)uploader didCreateDirectoryAtPath:(NSString*)path{
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(webUploader:didCreateDirectoryAtPath:)]) {
        
        [self.delegate webUploader:uploader didCreateDirectoryAtPath:path];
    }
    
    NSLog(@"JKWebServerManager-->didCreateDirectoryAtPath:%@", path);
}

#pragma mark
#pragma mark - GCDWebServerDelegate

/**
 *  This method is called after the server has successfully started.
 */
- (void)webServerDidStart:(GCDWebServer*)server{
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(webServerDidStart:)]) {
        
        [self.delegate webServerDidStart:server];
    }
    
    NSLog(@"JKWebServerManager-->webServerDidStart");
}

/**
 *  This method is called after the Bonjour registration for the server has
 *  successfully completed.
 *
 *  Use the "bonjourServerURL" property to retrieve the Bonjour address of the
 *  server.
 */
- (void)webServerDidCompleteBonjourRegistration:(GCDWebServer*)server{
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(webServerDidCompleteBonjourRegistration:)]) {
        
        [self.delegate webServerDidCompleteBonjourRegistration:server];
    }
    
    NSLog(@"JKWebServerManager-->webServerDidCompleteBonjourRegistration");
}

/**
 *  This method is called after the NAT port mapping for the server has been
 *  updated.
 *
 *  Use the "publicServerURL" property to retrieve the public address of the
 *  server.
 */
- (void)webServerDidUpdateNATPortMapping:(GCDWebServer*)server{
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(webServerDidUpdateNATPortMapping:)]) {
        
        [self.delegate webServerDidUpdateNATPortMapping:server];
    }
    
    NSLog(@"JKWebServerManager-->webServerDidUpdateNATPortMapping");
}

/**
 *  This method is called when the first GCDWebServerConnection is opened by the
 *  server to serve a series of HTTP requests.
 *
 *  A series of HTTP requests is considered ongoing as long as new HTTP requests
 *  keep coming (and new GCDWebServerConnection instances keep being opened),
 *  until before the last HTTP request has been responded to (and the
 *  corresponding last GCDWebServerConnection closed).
 */
- (void)webServerDidConnect:(GCDWebServer*)server{
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(webServerDidConnect:)]) {
        
        [self.delegate webServerDidConnect:server];
    }
    
    NSLog(@"JKWebServerManager-->webServerDidConnect");
}

/**
 *  This method is called when the last GCDWebServerConnection is closed after
 *  the server has served a series of HTTP requests.
 *
 *  The GCDWebServerOption_ConnectedStateCoalescingInterval option can be used
 *  to have the server wait some extra delay before considering that the series
 *  of HTTP requests has ended (in case there some latency between consecutive
 *  requests). This effectively coalesces the calls to -webServerDidConnect:
 *  and -webServerDidDisconnect:.
 */
- (void)webServerDidDisconnect:(GCDWebServer*)server{
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(webServerDidDisconnect:)]) {
        
        [self.delegate webServerDidDisconnect:server];
    }
    
    NSLog(@"JKWebServerManager-->webServerDidDisconnect");
}

/**
 *  This method is called after the server has stopped.
 */
- (void)webServerDidStop:(GCDWebServer*)server{
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(webServerDidStop:)]) {
        
        [self.delegate webServerDidStop:server];
    }
    
    NSLog(@"JKWebServerManager-->webServerDidStop");
}
@end
